Skip to content

Metrics, QC & all pipeline in longitudinal space (Stage 6 of #301)#317

Merged
nx10 merged 9 commits into
mainfrom
refactor/longitudinal-stage-6
Apr 17, 2026
Merged

Metrics, QC & all pipeline in longitudinal space (Stage 6 of #301)#317
nx10 merged 9 commits into
mainfrom
refactor/longitudinal-stage-6

Conversation

@nx10
Copy link
Copy Markdown
Contributor

@nx10 nx10 commented Apr 16, 2026

Summary

  • Metrics: rbc longitudinal metrics resolves per-regressor regressed_bold/cleaned_bold + brain mask from space-longitudinal functional derivatives, reads TR from the NIfTI header, and calls single_session_metrics unchanged. Reuses cross-sectional export_metrics for BIDS output naming (ALFF, fALFF, ReHo, atlas timeseries/correlations). CLI mirrors cross-sectional with --atlas (default schaefer_200) and --fwhm (default 6.0).
  • QC: rbc longitudinal qc computes Dice/Jaccard overlap between the anatomical brain mask and BOLD brain mask in longitudinal template space. Pass/fail threshold at Dice >= 0.85. Minimal scope per plan; no visualizations (tracked in Cross-sectional QC visualization pipeline #303/Longitudinal QC visualization pipeline #304).
  • All: rbc longitudinal all chains template -> anat -> func -> metrics -> qc. Template step writes to disk (cross-session), then per-session stages pass functional outputs in-memory to metrics and QC. CLI gains --regressor and --task flags.
  • Plumbing: process_anat/process_func now return their workflow outputs (AnatomicalLongOutputs/FunctionalLongOutputs) for in-memory handoff.
  • Tests: Tier-4 full_pipeline tests for metrics, QC, and the all-vs-sequential equivalence test under tests/full_pipeline/longitudinal/. Unit test dispatch tests updated from NotImplementedError checks to mock-based routing verification.

Ports metrics work from closed #297.

Closes the Stage 6 checkbox on #301.

Test plan

  • uv run ruff check passes on all changed files
  • uv run mypy passes on all changed modules
  • uv run pytest -m unit passes (780 passed)
  • uv run pytest -m integration --runner docker (nightly lane)
  • uv run pytest -m full_pipeline --runner docker for tests/full_pipeline/longitudinal/ (release lane)

nx10 and others added 2 commits April 16, 2026 16:46
Implement rbc longitudinal metrics: resolve per-regressor
regressed_bold/cleaned_bold + brain mask from space-longitudinal
functional derivatives, read TR from NIfTI header, and call
single_session_metrics unchanged. Reuse cross-sectional export_metrics
for BIDS output naming.

Co-authored-by: Janhavi Pillai <janhavipillai3@gmail.com>
QC: Dice/Jaccard overlap between anatomical and BOLD brain masks in
longitudinal space with pass/fail threshold (Dice >= 0.85). Minimal
scope per plan; viz tracked in #303/#304.

All: rbc longitudinal all chains template -> anat -> func -> metrics ->
qc. Template writes to disk (cross-session), then per-session stages
pass func outputs in-memory to metrics and QC.

CLI: Add --regressor and --task to rbc longitudinal all. Update
descriptions for metrics/qc (no longer placeholders). Update unit tests
to match (dispatch tests use mocks instead of NotImplementedError).

Tests: Tier-4 full_pipeline tests for longitudinal metrics, QC, and the
all-vs-sequential equivalence test under
tests/full_pipeline/longitudinal/.

process_anat/process_func now return their workflow outputs for
in-memory handoff.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 16, 2026

Coverage

Tests Skipped Failures Errors Time
781 0 💤 0 ❌ 0 🔥 11.142s ⏱️

nx10 added 5 commits April 16, 2026 17:34
The T1w suffix filter in run() excluded mask files from the DataFrame
passed to process_anat, so resolve_longitudinal_anat could never find
the brain mask. Remove the filter so both T1w and mask rows are grouped
together. Pre-existing bug from Stage 4 exposed by the new full_pipeline
tests.
Replace fragile DataFrame-based regressor discovery (which queried a
non-existent 'reg' column) with an explicit --regressor parameter,
matching the cross-sectional metrics CLI pattern.
The all fixture ran cross-sectional functional only for ses-test but
invoked rbc longitudinal all without --session-label, causing it to
iterate ses-retest (which has no functional derivatives) and crash on an
empty BOLD DataFrame.
Template generation needs all sessions to find multi-session subjects.
The session/task filters should only apply to per-session stages (anat,
func, metrics, qc), not to discover_template_inputs which requires the
full cross-session view.
nx10 added 2 commits April 16, 2026 21:15
TR handling:
- Promote resolve_tr/warn_implausible_tr to public API in metadata.py
- Replace bare _read_header_tr with _read_derivative_tr that pipes
  through resolve_tr for validation and plausibility warnings
- Add --tr override to rbc longitudinal metrics CLI, matching
  cross-sectional

FreeSurfer auth:
- Rename _setup_freesurfer_auth -> setup_freesurfer_auth and add to
  __all__ in template.py
- Import at module level in all.py instead of lazy private import

QC DataFrame assembly:
- Replace manual concat of session.anat + session.func + tpl_df with
  load_table call, matching cross-sectional qc.py pattern
@nx10 nx10 merged commit 8b3ee63 into main Apr 17, 2026
8 checks passed
@nx10 nx10 deleted the refactor/longitudinal-stage-6 branch April 17, 2026 01:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant